package com.cictec.middleware.tde.rm.mina.handler;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.PostConstruct;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cictec.middleware.tde.rm.SessionManager;
import com.cictec.middleware.tde.rm.disp.MessageHandler;
import com.cictec.middleware.tde.rm.disp.annotation.HandleMessages;
import com.cictec.middleware.tde.rm.protocol.TerminalMessage;
import com.cictec.middleware.tde.rm.protocol.rm.ProtocelConstants;
import com.cictec.middleware.tde.rm.protocol.rm.SendSequenceGenerator;
import com.impetus.annovention.ClasspathDiscoverer;
import com.impetus.annovention.listener.ClassAnnotationDiscoveryListener;

@Component
public class TerminalMessageHandler extends IoHandlerAdapter {

	private static Logger logger = LoggerFactory.getLogger(TerminalMessageHandler.class);

	private final AttributeKey SEQUENT_COUNTER = new AttributeKey(getClass(), "SeqentCounter");

	@Autowired
	private SessionManager sessionManager;

	private Map<Integer, MessageHandler> msgHandlers = new HashMap<Integer, MessageHandler>();

	@PostConstruct
	public void init() {
		logger.debug("加载接口处理");
		loadTaskRunners();
	}

	@Override
	public void sessionCreated(IoSession session) throws Exception {
		// 初始化发送序列号生成器
		session.setAttribute(ProtocelConstants.SESSION_SEND_SEQUENCE, new SendSequenceGenerator());
		session.setAttribute(SEQUENT_COUNTER, new Integer(0));
		sessionManager.registerSession(session);

	}

	@Override
	public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
		if (status == IdleStatus.BOTH_IDLE) {
			sessionManager.closeSession(session);
		}
	}

	@Override
	public void sessionClosed(IoSession session) throws Exception {
		sessionManager.unregisterSession(session);
	}

	@Override
	public void messageReceived(IoSession session, Object message) throws Exception {
		// 如果session中不包含传输协议，设置为锐明协议
		sessionManager.setProtocolByTerminalId(session, "rm");

		TerminalMessage tm = (TerminalMessage) message;
		dispatchMessage(session, tm);
	}

	protected void dispatchMessage(IoSession session, TerminalMessage tm) {
		logger.debug("准备调度消息 Session {} 消息ID(十六进制)：0x{}", tm.getSessionId(), Integer.toHexString(tm.getMessageId()));

		// 根据通讯协议获取对于的业务处理方法，处理方法在 com.cic.md.disp.receiver.handler 包下
		MessageHandler handler = getMessageHandler(tm);

		try {
			handler.handleMessage(tm, session);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("【TerminalMessageHandler】 调用接口错误 {}", e);
		}
	}

	@Override
	public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
		cause.printStackTrace();
		logger.warn("连接出现异常", cause);
	}

	/**
	 * 注册加载：根据通讯协议加载各个协议处理方法 【注解为 @HandleMessages】的处理方法
	 */
	public void loadTaskRunners() {
		logger.debug("加载终端消息接口 MessageHandler..开始");
		ClasspathDiscoverer discoverer = new ClasspathDiscoverer();
		discoverer.addAnnotationListener(new TaskRunnerAnnotationDiscoveryListener());
		discoverer.discover(true, false, false, true, true);
		logger.debug("加载终端消息接口 MessageHandler..完成");
	}

	public MessageHandler getMessageHandler(TerminalMessage msg) {
		return msgHandlers.get(getHandlerKey(msg));
	}

	public Integer getHandlerKey(TerminalMessage msg) {
		TerminalMessage tm = (TerminalMessage) msg;
		return tm.getMessageId();
	}

	public SessionManager getSessionManager() {
		return sessionManager;
	}

	public void setSessionManager(SessionManager sessionManager) {
		this.sessionManager = sessionManager;
	}

	@Autowired
	private Map<String, MessageHandler> messageHandlers;
	
	class TaskRunnerAnnotationDiscoveryListener implements ClassAnnotationDiscoveryListener {

		private HashMap<String, MessageHandler> getHandler(String clazz){
			
			HashMap<String, MessageHandler> handlers = new LinkedHashMap<String, MessageHandler>();
			for (MessageHandler handler : messageHandlers.values()) {
				if(clazz.equals(handler.getClass().getCanonicalName())){
					handlers.put(handler.getClass().getSimpleName(), handler);
				}
//				System.out.println(handler.getClass().getName());
//				System.out.println(handler.getClass().toString());
			}
			return handlers;
			
		}
		
		@Override
		public void discovered(String clazz, String annotation) {

			logger.info("Discovered Class(" + clazz + ") with Annotation(" + annotation + ")");
			try {
				Class<?> clz = Class.forName(clazz);

				HandleMessages hm = clz.getAnnotation(HandleMessages.class);
				if (hm != null) {
					int[] values = hm.value();

//					LinkedHashMap<String, MessageHandler> handlers = (LinkedHashMap<String, MessageHandler>) SpringContextHolder.getBean(Class.forName(clazz));
					HashMap<String, MessageHandler> handlers = getHandler(clazz);
					
					
					if (!handlers.isEmpty()) {
						Iterator<Entry<String, MessageHandler>> iter = handlers.entrySet().iterator();
						String beanName = null;
						MessageHandler msgHandler = null;
						while (iter.hasNext()) {
							Map.Entry<String, MessageHandler> entry = iter.next();
							String key = entry.getKey();
							msgHandler = entry.getValue();
							beanName = beanName == null ? key : beanName + "," + key;
						}
						for (Integer value : values) {
							msgHandlers.put(value, msgHandler);
						}

						if (handlers.size() > 1) {
							logger.warn("定义多个bean实例：{}, {}", clazz, beanName);
						}
					}
				} else {
					logger.error("没有找到类 {} 中 HandleMessages 定义", clazz);
				}
			} catch (ClassNotFoundException e) {
				logger.error("找不到类 {}", e.getMessage());
			}
		}

		@Override
		public String[] supportedAnnotations() {
			return new String[] { HandleMessages.class.getName() };
		}
	}

}
